<!DOCTYPE html>


<html lang="zh-CN">
  

    <head>
      <meta charset="utf-8" />
        
      <meta
        name="viewport"
        content="width=device-width, initial-scale=1, maximum-scale=1"
      />
      <title>Linux |  hangfei&#39;blog</title>
  <meta name="generator" content="hexo-theme-ayer">
      
      <link rel="shortcut icon" href="/favicon.ico" />
       
<link rel="stylesheet" href="/dist/main.css">

      <link
        rel="stylesheet"
        href="https://cdn.jsdelivr.net/gh/Shen-Yu/cdn/css/remixicon.min.css"
      />
      
<link rel="stylesheet" href="/css/custom.css">
 
      <script src="https://cdn.jsdelivr.net/npm/pace-js@1.0.2/pace.min.js"></script>
       
 

      <link
        rel="stylesheet"
        href="https://cdn.jsdelivr.net/npm/@sweetalert2/theme-bulma@5.0.1/bulma.min.css"
      />
      <script src="https://cdn.jsdelivr.net/npm/sweetalert2@11.0.19/dist/sweetalert2.min.js"></script>

      <!-- mermaid -->
      
      <script src="https://cdn.jsdelivr.net/npm/mermaid@8.9.2/dist/mermaid.min.js"></script>
      
      <style>
        .swal2-styled.swal2-confirm {
          font-size: 1.6rem;
        }
      </style>
    </head>
  </html>
</html>


<body>
  <div id="app">
    
      
    <main class="content on">
      <section class="outer">
  <article
  id="post-Linux"
  class="article article-type-post"
  itemscope
  itemprop="blogPost"
  data-scroll-reveal
>
  <div class="article-inner">
    
    <header class="article-header">
       
<h1 class="article-title sea-center" style="border-left:0" itemprop="name">
  Linux
</h1>
 

      
    </header>
     
    <div class="article-meta">
      <a href="/2022/06/01/Linux/" class="article-date">
  <time datetime="2022-06-01T13:47:40.897Z" itemprop="datePublished">2022-06-01</time>
</a>   
<div class="word_count">
    <span class="post-time">
        <span class="post-meta-item-icon">
            <i class="ri-quill-pen-line"></i>
            <span class="post-meta-item-text"> 字数统计:</span>
            <span class="post-count">6.5k</span>
        </span>
    </span>

    <span class="post-time">
        &nbsp; | &nbsp;
        <span class="post-meta-item-icon">
            <i class="ri-book-open-line"></i>
            <span class="post-meta-item-text"> 阅读时长≈</span>
            <span class="post-count">24 分钟</span>
        </span>
    </span>
</div>
 
    </div>
      
    <div class="tocbot"></div>




  
    <div class="article-entry" itemprop="articleBody">
       
  <p>Linux程序分为<strong>可执行文件</strong>和<strong>脚本程序</strong></p>
<h2 id="1、shell编程"><a href="#1、shell编程" class="headerlink" title="1、shell编程"></a>1、shell编程</h2><h3 id="1-1、变量"><a href="#1-1、变量" class="headerlink" title="1.1、变量"></a>1.1、变量</h3><ul>
<li>shell变量区分大小写</li>
<li>可以使用 echo $变量 来将变量内容输出在终端（给变量赋值时，如果字符串有空格，应该用引号括起来）</li>
</ul>
<pre class="line-numbers language-shell" data-language="shell"><code class="language-shell">salution&#x3D;&quot;yes day&quot;
echo $salution<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre>



<ul>
<li>使用read命令来将用户的输入赋值给一个变量</li>
</ul>
<pre class="line-numbers language-shell" data-language="shell"><code class="language-shell"># read salution
wie geht&#39;s?
# echo $salution<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span></span></code></pre>

<h3 id="1-2、命令"><a href="#1-2、命令" class="headerlink" title="1.2、命令"></a>1.2、命令</h3><ul>
<li>break命令<ul>
<li>使用break命令可以提前跳出for、while、until循环。</li>
<li>默认只跳出一层循环。</li>
</ul>
</li>
</ul>
<ul>
<li><p>：冒号命令</p>
<ul>
<li>冒号命令是一个空命令。偶尔被用于简化条件逻辑，相当于true的一个别名。</li>
<li>while：实现了一个无限循环</li>
</ul>
</li>
<li><p>continue命令</p>
<ul>
<li>这个命令会让for、while、until循环跳到下一次循环继续执行，循环变量取循环列表中的下一个值。</li>
<li>continue可以带一个可选的参数以希望执行的循环嵌套层数，也就是说可以部分跳出嵌套循环。（很少使用，导致脚本程序极难理解）</li>
</ul>
</li>
<li><p>.命令</p>
<ul>
<li><p>（.）命令用于在当前shell中执行命令：</p>
<ul>
<li>```shell<br>./shell_script<pre class="line-numbers language-none"><code class="language-none">
- echo命令

  - X&#x2F;Open建议现代shell中使用printf命令。
  - echo命令用来输出结尾带有换行符的字符串。

- eval命令

  - 允许你对参数进行求值。他是shell的内置命令，通常不会以单独的命令形式存在。

- exit n 命令

  - 使脚本以退出码n结束允许。
  - 退出码0表示成功，退出码1-125是脚本程序可以使用的错误代码。其余数字具有保留含义。（126：文件不可执行，127：命令未找到，128及以上：出现一个信号）

- export命令

  - 将作为他参数的变量导出到子shell中，并使之在子shell中有效。

- expr命令

  - expr命令将它的参数当做一个表达式来求值。它最常见的用法就是进行简单的数学运算。

- return命令

  - 作用是使函数返回

- set命令

  - 作用是为shell设置参数变量。

  - &#96;&#96;&#96;shell
    set $(date)<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></li>
</ul>
</li>
<li><p>​</p>
</li>
</ul>
</li>
</ul>
<h2 id="2、标准I-O库"><a href="#2、标准I-O库" class="headerlink" title="2、标准I/O库"></a>2、标准I/O库</h2><ul>
<li>fopen、fclose<ul>
<li>主要用于文件和终端的输入输出。</li>
<li>fopen在成功是会返回一个非空的FILE *指针，失败是返回NULL值</li>
<li>fclose关闭指定的文件流stream，使所有未写出的数据都写出。</li>
</ul>
</li>
<li>fread、fwrite<ul>
<li>fread用于从一个文件里读取数据。数据从文件流stream读到由ptr指向的数据缓冲区。返回成功读到数据缓冲区里的记录个数（不是字节数）。</li>
<li>fwrite:从指定的数据缓冲区里读取出数据记录，并将它们写到输出流中。返回值为成功写入的记录个数。</li>
<li>不推荐将fread和fwrite用于结构化数据。一部分原因是fwrite写的文件在不同计算机体系结构之间可能不具备可移植性。</li>
</ul>
</li>
<li>fflush-<ul>
<li>把文件流里未写出的数据立刻写出。在调用fclose函数时隐含的进行了一次flush操作，因此不必再调用fclose函数之前调用fflush。</li>
</ul>
</li>
<li>fseek-<ul>
<li>lseek系统调用对文件描述符fildes的读写指针进行设置，也就是说可以用它来设置文件的下一个读写位置。读写指针既可以被设置成为文件中的某个绝对位置，也可以把它设置为相对于当前位置或文件尾的某个相对位置。</li>
<li>fseek函数是与lseek系统调用对应的文件流函数。他在文件流里为下一次读写操作指定位置。lseek返回的是一个off_t数值，而fseek返回的是一个整数：0-表示成功，-1表示失败并设置error指出错误。</li>
</ul>
</li>
<li>fgetc、getc、getchar<ul>
<li>fgetc函数从文件流里取出下一个字节并把它作为一个字符返回。当它到达文件尾或者出现错误时，返回EOF。</li>
<li>getchar函数作用相当于getc，它从标准输入里读取下一个字符。</li>
</ul>
</li>
<li>fputc、putc、putchar<ul>
<li>fputc函数把一个字符写到一个输出文件流中。返回写入的值，如果写入失败，则返回EOF。</li>
<li>putc作用相当于fputc，但他可能被实现为一个宏。</li>
<li>putchar相当于putc，把单个字符写到标准输出。putchar和getchar都是将字符当做int型而不是char型来使用的。</li>
</ul>
</li>
<li>fgets、gets<ul>
<li>fgets从输入文件流stream里读取一个字符串。将读取到的字符串写到指定的字符串里。</li>
</ul>
</li>
<li>printf、fprintf、sprintf<ul>
<li>printf包含一个需要输出的普通字符和成为转换控制符代码的字符串，转换控制符规定了其他的参数应该以何种方式输出到何种地方。</li>
<li>fprint函数把自己的输出送到一个指定的文件流。</li>
<li>sprintf函数把自己的输出和一个结尾空字符写到作为参数传递过来的字符串里。</li>
<li>转换控制符<ul>
<li>%d,%i:以十进制格式输出一个整数。</li>
<li>%o,%x:以八进制或者十六进制格式输出一个整数。</li>
<li>%c:输出一个字符</li>
<li>%s：输出一个字符串。</li>
<li>%f:输出一个单精度浮点数。</li>
<li>%e:以科学计数法格式输出一个双精度浮点数。</li>
<li>%g：以通用格式输出一个双精度浮点数。</li>
</ul>
</li>
<li>字段限定符：负值的字段宽度表示数据在该字段里左对齐的格式输出。可变字段宽度用一个（*）来表示。%后以0开头表示数据前面要用0填充。<ul>
<li>printf不对数据字段进行截断，而是扩充数据字段以适应数据的宽度。因此打印一个比字段宽度长的字符串，数据字段会加宽。</li>
</ul>
</li>
</ul>
</li>
<li>scanf、fscanf、sscanf<ul>
<li>scanf函数读入的值将保存在相应的变量中。</li>
<li>转换控制符<ul>
<li>%d:读取十进制格式整数。</li>
<li>%o,%x:读取八进制或者十六进制格式整数。</li>
<li>%f、%e、%g:读取一个浮点数</li>
<li>%c:输出一个字符</li>
<li>%s：输出一个字符串。</li>
<li>%[]:读取一个字符集合</li>
<li>%e:以科学计数法格式输出一个双精度浮点数。</li>
<li>%g：以通用格式输出一个双精度浮点数。</li>
</ul>
</li>
</ul>
</li>
</ul>
<h2 id="3、使用curses函数库管理基于文本的屏幕"><a href="#3、使用curses函数库管理基于文本的屏幕" class="headerlink" title="3、使用curses函数库管理基于文本的屏幕"></a>3、使用curses函数库管理基于文本的屏幕</h2><h3 id="3-1-curses函数库的使用"><a href="#3-1-curses函数库的使用" class="headerlink" title="3.1 curses函数库的使用"></a>3.1 curses函数库的使用</h3><ul>
<li>curses函数库能够优化光标的移动并最小化需要对屏幕进行的刷新，从而也减少了必须向字符终端发送字符数目。</li>
</ul>
<ul>
<li>curses函数库用两个数据结构来映射终端屏幕，它们是stdscr和curscr。两者中，stdscr更重要。会在curses函数产生输出时被刷新。</li>
<li>所有的curses程序必须以initscr函数开始，以endwin函数结束。<ul>
<li>initscr函数在一个程序中只能调用一次。成功返回指向stdscr结构的指针；失败则会输出诊断错误信息并推出程序。</li>
<li>endwin成功返回OK，失败返回ERR。</li>
</ul>
</li>
<li>​</li>
</ul>
<h2 id="4、数据管理"><a href="#4、数据管理" class="headerlink" title="4、数据管理"></a>4、数据管理</h2><ul>
<li>动态内存管理：Linux可以做什么以及Linux不允许做什么。</li>
<li>文件锁定：协调锁、共享文件的锁定区域和避免死锁。</li>
<li>dbm数据库：一个大多数Linux系统都提供、基本的不基于SQL的数据库函数库。</li>
</ul>
<h3 id="4-1-内存管理"><a href="#4-1-内存管理" class="headerlink" title="4.1 内存管理"></a>4.1 内存管理</h3><p><strong>除了一些特殊的嵌入式应用程序外，Linux决不允许直接访问物理内存。</strong></p>
<p><strong>简单的内存分配</strong>：</p>
<pre class="line-numbers language-c" data-language="c"><code class="language-c"><span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">include</span><span class="token string">&lt;stdlib.h></span></span>
<span class="token keyword">void</span> <span class="token operator">*</span><span class="token function">malloc</span><span class="token punctuation">(</span><span class="token class-name">size_t</span> size<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">/*最常用的内存分配函数*/</span>
<span class="token keyword">void</span> <span class="token operator">*</span><span class="token function">calloc</span><span class="token punctuation">(</span><span class="token class-name">size_t</span> number_of_elements<span class="token punctuation">,</span>size_telement_size<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">void</span> <span class="token operator">*</span><span class="token function">realloc</span><span class="token punctuation">(</span><span class="token keyword">void</span> <span class="token operator">*</span>existing_memory<span class="token punctuation">,</span><span class="token class-name">size_t</span> new_size<span class="token punctuation">)</span><span class="token punctuation">;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span></span></code></pre>

<ul>
<li>Linux不要求包含mallac.c头文件，并且用来指定待分配内存字节数量的参数size不是一个简单的整型，通常是一个无符号整型。</li>
<li>malloc返回的是void指针，并且可以保证地址对齐，所以可以被转换为任何类型的指针</li>
</ul>
<p><strong>分配大量的内存</strong>：</p>
<ul>
<li>刚刚开始时，内核只是通过使用空闲的物理内存来满足应用程序的内存请求，当物理内存耗尽时，会开始交换空间。<ul>
<li>交换空间是一个在安装系统时分配的独立的磁盘区域。</li>
<li>内核会在物理内存和交换空间之间移动数据和程序代码，使得每次读写内存时数据看起来总像是已存在于物理内存中。</li>
<li>当应用程序耗尽所有物理内存和交换空间或者当最大栈长度被超过时，内核将拒绝此后的内存请求，并可能提前终止程序的运行。</li>
</ul>
</li>
<li>每个Linux系统中运行的程序都只能看到属于自己的内存映像，不同程序看到的内存映像不同。</li>
</ul>
<p><strong>calloc</strong>：为一个结构数组分配内存，需要把元素个数和每个元素的大小作为参数。他所分配的内存将全部初始化为0.calloc调用成功，会返回第一个元素的指针。</p>
<p><strong>realloc</strong>：用来改变先前已经分配的内存块的长度。他需要传递一个指向先前通过malloc、calloc或者realloc调用分配的内存的指针，然后根据new_size的值来改变其长度。<strong>内存被重新分配以后，应该使用新的指针去访问内存</strong>。</p>
<h3 id="4-2-文件锁定"><a href="#4-2-文件锁定" class="headerlink" title="4.2 文件锁定"></a>4.2 文件锁定</h3><h3 id="4-2-1-创建锁文件"><a href="#4-2-1-创建锁文件" class="headerlink" title="4.2.1 创建锁文件"></a>4.2.1 创建锁文件</h3><ul>
<li>许多应用程序只需要能够针对某个资源创建一个锁文件即可。然后其他程序就可以通过检查这个文件来判断他们自己是否被允许访问这个资源。</li>
</ul>
<ul>
<li>锁文件只是充当一个指示器的角色，程序间需要通过相互协作来使用他们。锁文件只是<strong>建议锁</strong>而不是<strong>强制锁</strong>。</li>
</ul>
<p>（适合用来控制对串行口等<strong>不经常访问的文件</strong>之类的资源独占式访问，不适合用于访问<strong>大型的共享文件</strong>。）</p>
<h3 id="4-2-2-区域锁定（文件段锁定-文件区域锁定）"><a href="#4-2-2-区域锁定（文件段锁定-文件区域锁定）" class="headerlink" title="4.2.2 区域锁定（文件段锁定/文件区域锁定）"></a>4.2.2 区域锁定（文件段锁定/文件区域锁定）</h3><p>文件中某个特定的部分被锁定，但是其他程序可以访问这个文件中的其他部分。</p>
<p>使用<strong>fcntl系统调用</strong>和使用lockf调用。</p>
<pre class="line-numbers language-c" data-language="c"><code class="language-c"><span class="token comment">/*
/*command:设置完成不同的任务选项--F_GETLK/F_SETLK/F_SETLKW*/</span>
<span class="token comment">/*flock_structrue:指向flock结构的指针*/</span>
<span class="token operator">*</span><span class="token operator">/</span>
<span class="token keyword">int</span> <span class="token function">fcntl</span><span class="token punctuation">(</span><span class="token keyword">int</span> fildes<span class="token punctuation">,</span> <span class="token keyword">int</span> command<span class="token punctuation">,</span> <span class="token keyword">struct</span> <span class="token class-name">flock</span> <span class="token operator">*</span>flock_structrue<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">//flock结构依赖具体的实现，至少包含成员</span>
<span class="token punctuation">&#123;</span>
  <span class="token keyword">short</span> l_type<span class="token punctuation">;</span>
  <span class="token keyword">short</span> l_whence<span class="token punctuation">;</span>
  <span class="token class-name">off_t</span> l_start<span class="token punctuation">;</span>
  <span class="token class-name">off_t</span> l_len<span class="token punctuation">;</span>
  <span class="token class-name">pid_t</span> l_pid<span class="token punctuation">;</span>
<span class="token punctuation">&#125;</span>
<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>

<p><strong>l_type</strong>成员取值定义在fcntl.h头文件中</p>
<ul>
<li>F_RDLCK:共享（或读）锁。多个不同的进程可以拥有文件同一个区域上的共享锁。只要有一个进程拥有了共享锁，那么就不会有另外的进程可以拥有该区域的独占锁。以“读”或者“读/写”方式打开文件。</li>
<li>F_UNLCK:解锁，清除锁。</li>
<li>F_WRLCK:独占（写）锁。一个进程可以拥有文件任意一个特定区域的独占锁。一旦有进程拥有了独占锁，其他的进程都无法在该区域获得任何类型的锁。以“写”或者“读/写”方式打开文件。</li>
</ul>
<p>**l_whence、l_start、l_len:**定义了文件中的一个区域，即一个连续的字节集合。</p>
<ul>
<li>l_whence：通常设置为SEEK_SET<ul>
<li>SEEK_SET:对应文件头；</li>
<li>SEEK_CUR：当前位置；</li>
<li>SEEK_END：文件尾</li>
</ul>
</li>
<li>l_start：该区域的第一个字节</li>
<li>l_len：定义了该区域的字节数。</li>
</ul>
<p>l_pid：用来记录持有锁的进程。</p>
<p>command:设置完成不同的任务选项</p>
<ul>
<li>F_GETLK：用于获取fildes打开的文件的锁信息。</li>
<li>F_SETLK：对fildes指向的文件的某个区域加锁或解锁。</li>
<li>F_SETLKW：与F_SETLK命令作用相同，但是在无法获取锁时，这个调用会一直等到能获取到锁或者受到信号为止。</li>
</ul>
<p>文件区域加锁之后，必须使用底层的<strong>read和write</strong>调用来访问文件中的数据，而不要使用更高级的fread和fwrite调用。fread和fwrite会对读写的数据进行缓存，执行一次fread会读取超过size的数据，并将多余的数据在函数库中进行缓存。</p>
<h2 id="5、进程和信号"><a href="#5、进程和信号" class="headerlink" title="5、进程和信号"></a>5、进程和信号</h2><ul>
<li>进程的结构、类型和调度</li>
<li>用不同的方法启动新进程</li>
<li>父进程、子进程和僵尸进程</li>
<li>什么是信号，怎么使用</li>
</ul>
<h3 id="5-1、进程的结构"><a href="#5-1、进程的结构" class="headerlink" title="5.1、进程的结构"></a>5.1、进程的结构</h3><p><strong>系统进程</strong>：使用ps 命令查看进程</p>
<p><img src="/images/%E8%BF%9B%E7%A8%8B%E8%AF%B4%E6%98%8E.png" alt="进程说明"></p>
<p>stat一列是用来表明进程的当前状态。</p>
<p><strong>进程调度</strong>：Linux内核用进程调度器来决定下一个时间片应该分配给哪个进程。判断依据为进程的优先级。</p>
<p>​    在一台单处理器计算机上，同一时间只能有一个进程可以运行，其他进程处于等待运行状态。每个程序轮到的运行时间是相当短暂的，故产生一种多个程序同时运行的假象。</p>
<h3 id="5-2、启动新进程"><a href="#5-2、启动新进程" class="headerlink" title="5.2、启动新进程"></a>5.2、启动新进程</h3><p>在程序内部可以采用system库函数来创建一个新进程。(在代码中使用<strong>并不理想</strong>)</p>
<pre class="line-numbers language-c" data-language="c"><code class="language-c"><span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">include</span><span class="token string">&lt;stdlib.h></span></span>
<span class="token keyword">int</span> <span class="token function">system</span><span class="token punctuation">(</span><span class="token keyword">const</span> <span class="token keyword">char</span> <span class="token operator">*</span> string<span class="token punctuation">)</span><span class="token punctuation">;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre>

<p>替换进程映像：<strong>exec系列函数</strong>可以将当前进程替换为一个新进程，新进程有<strong>path</strong>和<strong>file</strong>参数决定。可以使用exec函数将程序的执行从一个程序切换到另一个程序。（<strong>exec函数比system函数更有效</strong>）</p>
<p>复制进程映像：要想让进程同时执行多个函数，我么们可以使用多线程或者从原程序中创建一个完全分离的进程。</p>
<p>可以通过调用<strong>fork</strong>创建一个新进程。这个系统调用复制当前进程，在进程表中创建一个新的表项，新表项中的许多属性与当前进程相同。新进程几乎与原进程一模一样，执行代码也完全相同，但是新进程有自己的数据空间、环境和文件描述符。</p>
<pre class="line-numbers language-c" data-language="c"><code class="language-c"><span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">include</span><span class="token string">&lt;sys/types.h></span></span>
<span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">include</span><span class="token string">&lt;unistd.h></span></span>
<span class="token class-name">pid_t</span> <span class="token function">fork</span><span class="token punctuation">(</span><span class="token keyword">void</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span></span></code></pre>

<p><img src="/images/fork%E8%B0%83%E7%94%A8.png" alt="fork调用"></p>
<p>fork调用返回的是新的子进程的PID。新进程继续执行，子进程中的fork调用返回的是0。</p>
<h4 id="5-2-1、等待一个进程"><a href="#5-2-1、等待一个进程" class="headerlink" title="5.2.1、等待一个进程"></a>5.2.1、等待一个进程</h4><p>可以通过在父进程中调用wait函数让父进程等待子进程的结束。</p>
<pre class="line-numbers language-c" data-language="c"><code class="language-c"><span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">include</span><span class="token string">&lt;sys/types.h></span></span>
<span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">include</span><span class="token string">&lt;sys/wait.h></span></span>
<span class="token comment">/*返回子进程的PID*/</span>
<span class="token class-name">pid_t</span> <span class="token function">wait</span><span class="token punctuation">(</span><span class="token keyword">int</span> <span class="token operator">*</span> stat_loc<span class="token punctuation">)</span><span class="token punctuation">;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span></span></code></pre>

<h4 id="5-2-2僵尸进程"><a href="#5-2-2僵尸进程" class="headerlink" title="5.2.2僵尸进程"></a>5.2.2僵尸进程</h4><p>子进程终止时，它与父进程之间的关联还会保持，直到父进程也正常终止，或者父进程调用wait才告结束，因此进程表中代表子进程的表项不会立马释放。虽然子进程以及不再运行，但他任然存在与系统中，这时就成为了一个死进程（僵尸进程）。</p>
<h3 id="5-3信号"><a href="#5-3信号" class="headerlink" title="5.3信号"></a>5.3信号</h3><p>信号是UNIX和Linux系统响应某些条件而产生的一个事件。信号是由某些错误条件而生产的，如内存段冲突、浮点处理器错误或者非法指令等。它们由shell和终端处理器生成来引起中断，它们还可以作为在进程间传递消息或者修改行为的一种方式，明确的由一个进程发送给另一个进程。信号可以被<strong>生成</strong>、<strong>捕获</strong>、<strong>响应</strong>或者<strong>忽略</strong>。</p>
<p><img src="/images/%E4%BF%A1%E5%8F%B7.png" alt="信号"></p>
<p>如果进程接收到这些信号中的一个，但是事先没有安排捕获它，进程将会立刻终止。</p>
<p>程序可以用signal库函数来处理信号</p>
<pre class="line-numbers language-c" data-language="c"><code class="language-c"><span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">include</span><span class="token string">&lt;signal.h></span></span>
<span class="token comment">/*
signal是一个带sig和func两个参数的函数。准备捕获或忽略的信号由参数sig给出，接受到指定的信号后将要调用的函数由参数func给出，信号处理函数必须有一个int类型的参数（接受到的信号代码），并且返回类型为void
*/</span>
<span class="token keyword">void</span> <span class="token punctuation">(</span><span class="token operator">*</span><span class="token function">signal</span><span class="token punctuation">(</span><span class="token keyword">int</span> sig<span class="token punctuation">,</span> <span class="token keyword">void</span> <span class="token punctuation">(</span><span class="token operator">*</span>func<span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token keyword">int</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token keyword">int</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span></span></code></pre>

<pre class="line-numbers language-c" data-language="c"><code class="language-c"><span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">include</span><span class="token string">&lt;signal.h></span></span>
<span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">include</span><span class="token string">&lt;stdlib.h></span></span>
<span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">include</span><span class="token string">&lt;stdio.h></span></span>
<span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">include</span><span class="token string">&lt;unistd.h></span></span>
<span class="token comment">/*对通过参数sig传递进来的信号做出相应。信号出现时，程序调用该函数。*/</span>
<span class="token keyword">void</span> <span class="token function">ouch</span><span class="token punctuation">(</span><span class="token keyword">int</span> sig<span class="token punctuation">)</span>
<span class="token punctuation">&#123;</span>
    <span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"OUCH - I got signal %d\r\n"</span><span class="token punctuation">,</span> sig<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">(</span><span class="token keyword">void</span><span class="token punctuation">)</span> <span class="token function">signal</span><span class="token punctuation">(</span>SIGINT<span class="token punctuation">,</span>SIG_DFL<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">&#125;</span>
<span class="token keyword">int</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">&#123;</span>
    <span class="token punctuation">(</span><span class="token keyword">void</span><span class="token punctuation">)</span> <span class="token function">signal</span><span class="token punctuation">(</span>SIGINT<span class="token punctuation">,</span>ouch<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">while</span> <span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span>
    <span class="token punctuation">&#123;</span>
        <span class="token comment">/* code */</span>
        <span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"Hello World!\r\n"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token function">sleep</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>
    
<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>

<p>一般不使用signal接口，在程序中应该使用<strong>sigaction</strong>函数，它定义更清晰、执行更可靠。</p>
<pre class="line-numbers language-c" data-language="c"><code class="language-c"><span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">include</span><span class="token string">&lt;signal.h></span></span>
<span class="token keyword">int</span> <span class="token function">sigaction</span><span class="token punctuation">(</span><span class="token keyword">int</span> sig<span class="token punctuation">,</span> <span class="token keyword">const</span> <span class="token keyword">struct</span> <span class="token class-name">sigaction</span> <span class="token operator">*</span>act<span class="token punctuation">,</span> <span class="token keyword">struct</span> <span class="token class-name">sigaction</span> <span class="token operator">*</span>oact<span class="token punctuation">)</span><span class="token punctuation">;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre>

<p>结构定义在signal.h中，它的作用是定义在接受到参数sig指定的信号后应该采取的行动。该结构至少包含以下几个成员：</p>
<p><img src="/images/sigaction.png" alt="sigaction"></p>
<h4 id="5-3-1发送信号"><a href="#5-3-1发送信号" class="headerlink" title="5.3.1发送信号"></a>5.3.1发送信号</h4><p>进程可以通过调用<strong>kill</strong>函数向包含它本身在内的其他进程发送一个信号。如果程序没有发送该信号的权限，对kill函数的调用就会失败。（原因通常是目标进程由另一个用户所拥有。）</p>
<p>alarm函数：用来在second秒之后安排发送一个SIGALRM信号。但是由于处理的延时和时间调度的不确定性，实际闹钟时间将比预先安排的要稍微拖后一点。将seconds设置为0，将取消所有已设置的闹钟请求。如果在接受到SIGALRM信号之前再次调用alarm函数，则闹钟开始重新计时。每个进程只能有一个闹钟时间。</p>
<p>pause函数：将程序挂起直到程序接收到一个信号时，预设好的信号处理函数将开始运行。</p>
<h4 id="5-3-2信号集"><a href="#5-3-2信号集" class="headerlink" title="5.3.2信号集"></a>5.3.2信号集</h4><pre class="line-numbers language-c" data-language="c"><code class="language-c"><span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">include</span><span class="token string">&lt;signal.h></span></span>
<span class="token comment">/*从信号集中增加给定的信号signo*/</span>
<span class="token keyword">int</span> <span class="token function">sigaddset</span><span class="token punctuation">(</span><span class="token class-name">sigset_t</span> <span class="token operator">*</span>set<span class="token punctuation">,</span> <span class="token keyword">int</span> signo<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">/*将信号集初始化为空*/</span>
<span class="token keyword">int</span> <span class="token function">sigemptyset</span><span class="token punctuation">(</span><span class="token class-name">sigset_t</span> <span class="token operator">*</span>set<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">/*将信号集初始化为包含所有已定义的信号*/</span>
<span class="token keyword">int</span> <span class="token function">sigfillset</span><span class="token punctuation">(</span><span class="token class-name">sigset_t</span> <span class="token operator">*</span>set<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">/*从信号集中删除给定的信号signo*/</span>
<span class="token keyword">int</span> <span class="token function">sigdelset</span><span class="token punctuation">(</span><span class="token class-name">sigset_t</span> <span class="token operator">*</span> set<span class="token punctuation">,</span> <span class="token keyword">int</span> signo<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">/*判断一个给定信号是否是一个信号集的成员:是返回1，不是返回0，无效信号返回-1*/</span>
<span class="token keyword">int</span> <span class="token function">sigismember</span><span class="token punctuation">(</span><span class="token class-name">sigset_t</span> <span class="token operator">*</span> set<span class="token punctuation">,</span> <span class="token keyword">int</span> signo<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">/*负责进程的信号屏蔽字的设置或者检查*/</span>
<span class="token keyword">int</span> <span class="token function">sigprocmask</span><span class="token punctuation">(</span><span class="token keyword">int</span> how<span class="token punctuation">,</span><span class="token keyword">const</span> <span class="token class-name">sigset_t</span> <span class="token operator">*</span>set<span class="token punctuation">,</span><span class="token class-name">sigset_t</span> <span class="token operator">*</span>oset<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">/*将被阻塞的信号中停留在待处理状态的一组信号写到参数set指向的信号集中*/</span>
<span class="token keyword">int</span> <span class="token function">sigpending</span><span class="token punctuation">(</span><span class="token class-name">sigset_t</span> <span class="token operator">*</span>set<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">/*将自己挂起，指导信号集中的一个信号到达为止*/</span>
<span class="token keyword">int</span> <span class="token function">sigsuspend</span><span class="token punctuation">(</span><span class="token keyword">const</span> <span class="token class-name">sigset_t</span> <span class="token operator">*</span>sigmask<span class="token punctuation">)</span><span class="token punctuation">;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>

<h2 id="6、线程"><a href="#6、线程" class="headerlink" title="6、线程"></a>6、线程</h2><ul>
<li>在进程中创建新线程</li>
<li>在一个进程中同步线程之间的数据访问</li>
<li>修改线程的属性</li>
<li>在同一个进程中，从一个线程中控制另一个线程</li>
</ul>
<p>在一个程序中的多个执行路线叫<strong>线程</strong>：进程内部的一个控制序列。</p>
<p>线程优缺点：</p>
<ul>
<li>优点：<ul>
<li>新线程的创建代价比新进程小</li>
<li>能让程序看起来在同时做多件事情</li>
<li>能将程序的几个部分分成多个线程执行</li>
<li>线程之间的切换需要操作系统做的工作要比进程之间的切换少得多</li>
</ul>
</li>
<li>缺点：<ul>
<li>编程需要很仔细</li>
<li>调试困难</li>
<li>对硬件有一定的要求</li>
</ul>
</li>
</ul>
<p>创建一个新线程：</p>
<pre class="line-numbers language-c" data-language="c"><code class="language-c"><span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">include</span><span class="token string">&lt;pthread.h></span></span>
<span class="token comment">/*
*thread:指向pthread_t类型数据结构的指针
*attr:用于设置线程的属性，一般不需要特殊的属性，只需要设置为NULL即可
*
*/</span>
<span class="token keyword">int</span> <span class="token function">pthread_create</span><span class="token punctuation">(</span><span class="token class-name">pthread_t</span> <span class="token operator">*</span>thread<span class="token punctuation">,</span> <span class="token class-name">pthread_attr_t</span> <span class="token operator">*</span>attr<span class="token punctuation">,</span> <span class="token keyword">void</span> <span class="token operator">*</span><span class="token punctuation">(</span><span class="token operator">*</span>start_routine<span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token keyword">void</span> <span class="token operator">*</span><span class="token punctuation">)</span><span class="token punctuation">,</span><span class="token keyword">void</span> <span class="token operator">*</span>arg<span class="token punctuation">)</span><span class="token punctuation">;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>

<p>终止线程：</p>
<pre class="line-numbers language-c" data-language="c"><code class="language-c"><span class="token keyword">void</span> <span class="token function">pthread_exit</span><span class="token punctuation">(</span><span class="token keyword">void</span> <span class="token operator">*</span>retval<span class="token punctuation">)</span><span class="token punctuation">;</span><span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre>

<h3 id="6-1同步"><a href="#6-1同步" class="headerlink" title="6.1同步"></a>6.1同步</h3><h4 id="6-1-1用信号量同步"><a href="#6-1-1用信号量同步" class="headerlink" title="6.1.1用信号量同步"></a>6.1.1用信号量同步</h4><ul>
<li>二进制信号量<ul>
<li>只有0和1两种取值。保护一段代码，使其每次只能被一个执行线程运行。</li>
</ul>
</li>
<li>计数信号量<ul>
<li>有更大的取值范围，可以允许有限数目的线程执行一段指定的代码。（不常用）</li>
</ul>
</li>
</ul>
<pre class="line-numbers language-c" data-language="c"><code class="language-c"><span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">include</span><span class="token string">&lt;semaphore.h></span></span>
<span class="token comment">/*初始化函数*/</span>
<span class="token comment">/*
*pshared:控制信号量的类型，0：表示信号量是当前进程的局部信号量，否则这个信号量可以在多个进程之间共享。
*/</span>
<span class="token keyword">int</span> <span class="token function">sem_init</span><span class="token punctuation">(</span><span class="token class-name">sem_t</span> <span class="token operator">*</span>sem<span class="token punctuation">,</span> <span class="token keyword">int</span> pshared<span class="token punctuation">,</span> <span class="token keyword">unsigned</span> <span class="token keyword">int</span> value<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">/*以原子操作的方式给信号量的值减1，等到信号量出现非零值才开始操作，否则会一直等待。*/</span>
<span class="token keyword">int</span> <span class="token function">sem_wait</span><span class="token punctuation">(</span><span class="token class-name">sem_t</span> <span class="token operator">*</span> sem<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">/*以原子操作的方式给信号量的值加1：两个线程企图给一个信号量加1，两个进程之间互不干扰，最后信号量值被加2*/</span>
<span class="token keyword">int</span> <span class="token function">sem_post</span><span class="token punctuation">(</span><span class="token class-name">sem_t</span> <span class="token operator">*</span> sem<span class="token punctuation">)</span><span class="token punctuation">;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>

<h3 id="6-1-2用互斥量进行同步"><a href="#6-1-2用互斥量进行同步" class="headerlink" title="6.1.2用互斥量进行同步"></a>6.1.2用互斥量进行同步</h3><p>它允许程序员锁住某个对象，使得每次只能有一个线程访问它。为了控制对关键代码的访问，必须在进入这段代码之前锁住一个互斥量，然后在完成操作之后解锁它。</p>
<pre class="line-numbers language-c" data-language="c"><code class="language-c"><span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">include</span><span class="token string">&lt;pthread.h></span></span>
<span class="token keyword">int</span> <span class="token function">pthread_mutex_init</span><span class="token punctuation">(</span>pthread_mutex <span class="token operator">*</span> mutex<span class="token punctuation">,</span><span class="token keyword">const</span> <span class="token class-name">pthread_mutexattr_t</span> <span class="token operator">*</span>mutexattr<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> <span class="token function">pthread_mutex_lock</span><span class="token punctuation">(</span>pthread_mutex <span class="token operator">*</span> mutex<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> <span class="token function">pthread_mutex_unlock</span><span class="token punctuation">(</span>pthread_mutex <span class="token operator">*</span> mutex<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> <span class="token function">pthread_mutex_destroy</span><span class="token punctuation">(</span>pthread_mutex <span class="token operator">*</span> mutex<span class="token punctuation">)</span><span class="token punctuation">;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span></span></code></pre>

<p>如果程序试图对一个已经加了锁的互斥量调用pthread_mutex_lock函数，程序就会被阻塞，而又因为拥有互斥量的这个线程正是现在被阻塞的线程，所以互斥量就永远不会被解锁，程序也就进入了<strong>死锁状态</strong>。</p>
<h3 id="6-2线程的属性"><a href="#6-2线程的属性" class="headerlink" title="6.2线程的属性"></a>6.2线程的属性</h3><p><strong>脱离线程</strong>：在主线程为用户提供服务的同时创建第二个进程，第二个进程的工作结束可以直接终止，并不需要再回到主线程中.</p>
<p>相关函数：</p>
<pre class="line-numbers language-c" data-language="c"><code class="language-c"><span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">include</span><span class="token string">&lt;pthread.h></span></span>
<span class="token keyword">int</span> <span class="token function">pthread_attr_init</span><span class="token punctuation">(</span><span class="token class-name">pthread_attr_t</span> <span class="token operator">*</span> attr<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> <span class="token function">pthread_attr_setdetachstate</span><span class="token punctuation">(</span><span class="token class-name">pthread_attr_t</span> <span class="token operator">*</span> attr<span class="token punctuation">,</span> <span class="token keyword">int</span> detachstate<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> <span class="token function">pthread_attr_getdetachstate</span><span class="token punctuation">(</span><span class="token keyword">const</span> <span class="token class-name">pthread_attr_t</span> <span class="token operator">*</span> attr<span class="token punctuation">,</span> <span class="token keyword">int</span> detachstate<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> <span class="token function">pthread_attr_setschedpolicy</span><span class="token punctuation">(</span><span class="token class-name">pthread_attr_t</span> <span class="token operator">*</span> attr<span class="token punctuation">,</span> <span class="token keyword">int</span> policy<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> <span class="token function">pthread_attr_getschedpolicy</span><span class="token punctuation">(</span><span class="token class-name">pthread_attr_t</span> <span class="token operator">*</span> attr<span class="token punctuation">,</span> <span class="token keyword">int</span> policy<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> <span class="token function">pthread_attr_setschedparam</span><span class="token punctuation">(</span><span class="token class-name">pthread_attr_t</span> <span class="token operator">*</span> attr<span class="token punctuation">,</span> <span class="token keyword">const</span> <span class="token keyword">struct</span> <span class="token class-name">sched_param</span> <span class="token operator">*</span>param<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> <span class="token function">pthread_attr_getschedparam</span><span class="token punctuation">(</span><span class="token class-name">pthread_attr_t</span> <span class="token operator">*</span> attr<span class="token punctuation">,</span> <span class="token keyword">const</span> <span class="token keyword">struct</span> <span class="token class-name">sched_param</span> <span class="token operator">*</span>param<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> <span class="token function">pthread_attr_setinheritsched</span><span class="token punctuation">(</span><span class="token class-name">pthread_attr_t</span> <span class="token operator">*</span> attr<span class="token punctuation">,</span> <span class="token keyword">int</span> <span class="token operator">*</span>inherit<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> <span class="token function">pthread_attr_getinheritsched</span><span class="token punctuation">(</span><span class="token class-name">pthread_attr_t</span> <span class="token operator">*</span> attr<span class="token punctuation">,</span> <span class="token keyword">int</span> <span class="token operator">*</span>inherit<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> <span class="token function">pthread_attr_setscope</span><span class="token punctuation">(</span><span class="token class-name">pthread_attr_t</span> <span class="token operator">*</span> attr<span class="token punctuation">,</span> <span class="token keyword">int</span> <span class="token operator">*</span>scope<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> <span class="token function">pthread_attr_getscope</span><span class="token punctuation">(</span><span class="token class-name">pthread_attr_t</span> <span class="token operator">*</span> attr<span class="token punctuation">,</span> <span class="token keyword">int</span> <span class="token operator">*</span>scope<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> <span class="token function">pthread_attr_setstacksize</span><span class="token punctuation">(</span><span class="token class-name">pthread_attr_t</span> <span class="token operator">*</span> attr<span class="token punctuation">,</span> <span class="token keyword">int</span> <span class="token operator">*</span>scope<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> <span class="token function">pthread_attr_getstacksize</span><span class="token punctuation">(</span><span class="token class-name">pthread_attr_t</span> <span class="token operator">*</span> attr<span class="token punctuation">,</span> <span class="token keyword">int</span> <span class="token operator">*</span>scope<span class="token punctuation">)</span><span class="token punctuation">;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>

<ul>
<li>detachstate:允许我们无需对线程进行重新合并。</li>
<li>schedpolicy：控制线程的调度方式。</li>
<li>schedparam：这个属性是和schedpolicy属性结合使用的，它可以对以sched_other策略运行的线程的调度进行控制。</li>
<li>inheritsched：有两个取值<ul>
<li>pthread_explicit：表示调度由属性明确的设置（默认取值）</li>
<li>pthread_inherit_sched：新线程将沿用其创建者所使用的参数。</li>
</ul>
</li>
<li>scope：控制一个线程调度的计算方式。</li>
<li>stacksize：控制线程创建的栈大小（字节）。</li>
</ul>
<h3 id="6-3取消一个线程"><a href="#6-3取消一个线程" class="headerlink" title="6.3取消一个线程"></a>6.3取消一个线程</h3><p>线程可以在被要求终止时改变其行为。</p>
<p>线程终止的函数：</p>
<pre class="line-numbers language-c" data-language="c"><code class="language-c"><span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">include</span><span class="token string">&lt;pthread.h></span></span>
<span class="token comment">/*提供一个线程标识符，我们就能发送请求来取消它*/</span>
<span class="token keyword">int</span> <span class="token function">pthread_cancel</span><span class="token punctuation">(</span><span class="token class-name">pthread_t</span> thread<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">/*
*state:PTHREAD_CANCEL_ENABLE,允许线程接收取消请求；*PTHREAD_CANCEL_DISABLE，忽略取消请求。
*oldstate：用于获取先前的取消状态。
*/</span>
<span class="token keyword">int</span> <span class="token function">pthread_setcancelstate</span><span class="token punctuation">(</span><span class="token keyword">int</span> state<span class="token punctuation">,</span> <span class="token keyword">int</span> <span class="token operator">*</span>oldstate<span class="token punctuation">)</span><span class="token punctuation">;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>

<p>如果取消请求被接受了，线程就可以进入到第二个控制层次。</p>
<pre class="line-numbers language-c" data-language="c"><code class="language-c"><span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">include</span><span class="token string">&lt;pthread.h></span></span>
<span class="token comment">/*
*type的取值：
*PTHREAD_CANCEL_ASYNCHRONOUS:将使得在接受到取消请求后立即采取行动；
*PTHREAD_CANCEL_DEFERRED：它将使得在接收到取消请求后一直等待直到线程执行了一些函数之一才会采取行动。
*old参数可以保存先前的状态，如果不想直到先前的状态可以穿NULL；
*/</span>
<span class="token keyword">int</span> <span class="token function">pthread_setcanceltype</span><span class="token punctuation">(</span><span class="token keyword">int</span> type<span class="token punctuation">,</span><span class="token keyword">int</span> <span class="token operator">*</span>oldtype<span class="token punctuation">)</span><span class="token punctuation">;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>

<h2 id="7、进程间通信：管道"><a href="#7、进程间通信：管道" class="headerlink" title="7、进程间通信：管道"></a>7、进程间通信：管道</h2><ul>
<li>管道的定义</li>
<li>进程管道</li>
<li>管道调用</li>
<li>父进程和子进程</li>
<li>命名管道：FIFO</li>
<li>客户/服务器架构</li>
</ul>
<p>管道：当从一个进程连接数据流到另一个进程时，就称为<strong>管道</strong></p>
<h3 id="7-1进程管道"><a href="#7-1进程管道" class="headerlink" title="7.1进程管道"></a>7.1进程管道</h3><ul>
<li>popen函数</li>
<li>PClose函数</li>
</ul>
<pre class="line-numbers language-c" data-language="c"><code class="language-c"><span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">include</span><span class="token string">&lt;stdio.h></span></span>
<span class="token comment">/*
*open_mode:只能取r和w
****r:被调用程序的输出就可以被调用程序使用，调用程序利用popen函数返回的FILE*文件流指针就可以通过常用的stdio库函数来读取被调用程序的输出。
****w:调用程序就可以用fwrite调用向被调用程序发送数据，而被调用程序可以在自己的标准输入上读取这些数据。
*
*/</span>
FILE <span class="token operator">*</span><span class="token function">popen</span><span class="token punctuation">(</span><span class="token keyword">const</span> <span class="token keyword">char</span> <span class="token operator">*</span> command<span class="token punctuation">,</span> <span class="token keyword">const</span> <span class="token keyword">char</span> <span class="token operator">*</span>open_mode<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">/*
*pclose函数：用popen启动的进程结束时，我们可以用PClose函数关闭与之关联的文件流。
*/</span>
<span class="token keyword">int</span> <span class="token function">pclose</span><span class="token punctuation">(</span>FILE <span class="token operator">*</span> stream_close<span class="token punctuation">)</span><span class="token punctuation">;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>



<p>popen函数：允许一个程序将另一个程序作为新进程来启动，并且可以传递数据给它或者通过它接收数据。</p>
<h4 id="7-1-1实现popen"><a href="#7-1-1实现popen" class="headerlink" title="7.1.1实现popen"></a>7.1.1实现popen</h4><p>请求popen调用运行一个程序时，它首先启动shell，然后将command字符串作为一个参数传递给它。</p>
<ul>
<li>优点：在启动程序之前，先启动shell来分析命令字符串，就可以使用各种shell拓展在程序启动之前就全部完成。它允许我们通过popen启动非常复杂的shell命令。</li>
<li>缺点：针对每一个popen调用，不仅要启动一个被请求的程序，还要启动一个shell，每个popen调用将多启动两个进程，导致popen函数的调用成本较高，对目标命令的调用比正常方式慢一些。</li>
</ul>
<h3 id="7-2pipe调用"><a href="#7-2pipe调用" class="headerlink" title="7.2pipe调用"></a>7.2pipe调用</h3><p>pipe函数在两个程序之间传递数据时不需要启动一个shell来解释请求的命令。该函数在数组中填写两个新的文件描述符后返回0，如果失败则返回-1并设置errno来表明失败的原因。</p>
<ul>
<li>EMFILE：进程使用的文件描述符过多</li>
<li>ENFILE：系统的文件表已满</li>
<li>EFAULT：文件描述符无效</li>
</ul>
<pre class="line-numbers language-c" data-language="c"><code class="language-c"><span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">include</span><span class="token string">&lt;unistd.h></span></span>
<span class="token comment">/*
*参数是一个由两个整数类型的文件描述符组成的数组的指针。
*/</span>
<span class="token keyword">int</span> <span class="token function">pipe</span><span class="token punctuation">(</span><span class="token keyword">int</span> file_descriptor<span class="token punctuation">[</span><span class="token number">2</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span></span></code></pre>

<p>两个返回的文件描述符以一种特殊的方式连接起来，写在file_descriptor[1]的所有数据都可以从file_descriptor[0]读回来。处理方式采用<strong>先进先出</strong>。一般采用file_descriptor[1]写数据，file_descriptor[0]读数据，如果不这样可能会调用失败并返回-1。</p>
<p>pipe函数调用采用的是<strong>文件描述符</strong>而不是文件流，因此必须使用底层的<strong>read和write</strong>调用来访问数据，而不能用文件流库函数fread和fwrite。</p>
<h3 id="7-3父进程和子进程"><a href="#7-3父进程和子进程" class="headerlink" title="7.3父进程和子进程"></a>7.3父进程和子进程</h3><p>父进程和子进程之间的数据读写关系：父进程将数据通过文件描述符file_pipes[1]写进管道，子进程通过file_pipes[0]从管道中读取数据</p>
<p><img src="/images/pipe.png" alt="pipe"></p>
 
      <!-- reward -->
      
    </div>
    

    <!-- copyright -->
    
    <div class="declare">
      <ul class="post-copyright">
        <li>
          <i class="ri-copyright-line"></i>
          <strong>版权声明： </strong>
          
          本博客所有文章除特别声明外，著作权归作者所有。转载请注明出处！
          
        </li>
      </ul>
    </div>
    
    <footer class="article-footer">
       
<div class="share-btn">
      <span class="share-sns share-outer">
        <i class="ri-share-forward-line"></i>
        分享
      </span>
      <div class="share-wrap">
        <i class="arrow"></i>
        <div class="share-icons">
          
          <a class="weibo share-sns" href="javascript:;" data-type="weibo">
            <i class="ri-weibo-fill"></i>
          </a>
          <a class="weixin share-sns wxFab" href="javascript:;" data-type="weixin">
            <i class="ri-wechat-fill"></i>
          </a>
          <a class="qq share-sns" href="javascript:;" data-type="qq">
            <i class="ri-qq-fill"></i>
          </a>
          <a class="douban share-sns" href="javascript:;" data-type="douban">
            <i class="ri-douban-line"></i>
          </a>
          <!-- <a class="qzone share-sns" href="javascript:;" data-type="qzone">
            <i class="icon icon-qzone"></i>
          </a> -->
          
          <a class="facebook share-sns" href="javascript:;" data-type="facebook">
            <i class="ri-facebook-circle-fill"></i>
          </a>
          <a class="twitter share-sns" href="javascript:;" data-type="twitter">
            <i class="ri-twitter-fill"></i>
          </a>
          <a class="google share-sns" href="javascript:;" data-type="google">
            <i class="ri-google-fill"></i>
          </a>
        </div>
      </div>
</div>

<div class="wx-share-modal">
    <a class="modal-close" href="javascript:;"><i class="ri-close-circle-line"></i></a>
    <p>扫一扫，分享到微信</p>
    <div class="wx-qrcode">
      <img src="//api.qrserver.com/v1/create-qr-code/?size=150x150&data=http://www.harfe.icu/2022/06/01/Linux/" alt="微信分享二维码">
    </div>
</div>

<div id="share-mask"></div>  
    </footer>
  </div>

   
  <nav class="article-nav">
    
      <a href="/2022/06/01/%E5%BC%80%E5%8F%91%E5%B7%A5%E5%85%B7%E4%BB%A5%E5%8F%8A%E8%B0%83%E8%AF%95/" class="article-nav-link">
        <strong class="article-nav-caption">上一篇</strong>
        <div class="article-nav-title">
          
            开发工具及调试
          
        </div>
      </a>
    
    
      <a href="/2022/03/06/%E5%8F%8D%E5%B0%84%E6%9C%BA%E5%88%B6/" class="article-nav-link">
        <strong class="article-nav-caption">下一篇</strong>
        <div class="article-nav-title">反射机制</div>
      </a>
    
  </nav>

   
<!-- valine评论 -->
<div id="vcomments-box">
  <div id="vcomments"></div>
</div>
<script src="//cdn1.lncld.net/static/js/3.0.4/av-min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/valine@1.4.14/dist/Valine.min.js"></script>
<script>
  new Valine({
    el: "#vcomments",
    app_id: "naIjOvCa6fRj0wYNsOmHOipt-gzGzoHsz",
    app_key: "m6dupJxtpd3hiAmudK081SaM",
    path: window.location.pathname,
    avatar: "monsterid",
    placeholder: "给我的文章加点评论吧~",
    recordIP: true,
  });
  const infoEle = document.querySelector("#vcomments .info");
  if (infoEle && infoEle.childNodes && infoEle.childNodes.length > 0) {
    infoEle.childNodes.forEach(function (item) {
      item.parentNode.removeChild(item);
    });
  }
</script>
<style>
  #vcomments-box {
    padding: 5px 30px;
  }

  @media screen and (max-width: 800px) {
    #vcomments-box {
      padding: 5px 0px;
    }
  }

  #vcomments-box #vcomments {
    background-color: #fff;
  }

  .v .vlist .vcard .vh {
    padding-right: 20px;
  }

  .v .vlist .vcard {
    padding-left: 10px;
  }
</style>

 
   
     
</article>

</section>
      <footer class="footer">
  <div class="outer">
    <ul>
      <li>
        Copyrights &copy;
        2021-2022
        <i class="ri-heart-fill heart_icon"></i> zhenghangfei
      </li>
    </ul>
    <ul>
      <li>
        
      </li>
    </ul>
    <ul>
      <li>
        
        
        <span>
  <span><i class="ri-user-3-fill"></i>访问人数:<span id="busuanzi_value_site_uv"></span></span>
  <span class="division">|</span>
  <span><i class="ri-eye-fill"></i>浏览次数:<span id="busuanzi_value_page_pv"></span></span>
</span>
        
      </li>
    </ul>
    <ul>
      
    </ul>
    <ul>
      
      <li>
          <img src="/images/beian.png"></img>
          <a href="https://beian.miit.gov.cn/" target="_black" rel="nofollow">鄂ICP备2022003225号-1</a>
      </li>
        
    </ul>
    <ul>
      <li>
        <!-- cnzz统计 -->
        
        <script type="text/javascript" src='https://s9.cnzz.com/z_stat.php?id=1278069914&amp;web_id=1278069914'></script>
        
      </li>
    </ul>
  </div>
</footer>    
    </main>
    <div class="float_btns">
      <div class="totop" id="totop">
  <i class="ri-arrow-up-line"></i>
</div>

<div class="todark" id="todark">
  <i class="ri-moon-line"></i>
</div>

    </div>
    <aside class="sidebar on">
      <button class="navbar-toggle"></button>
<nav class="navbar">
  
  <div class="logo">
    <a href="/"><img src="/images/ayer-side.svg" alt="hangfei&#39;blog"></a>
  </div>
  
  <ul class="nav nav-main">
    
    <li class="nav-item">
      <a class="nav-item-link" href="/">主页</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/archives">归档</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/about">关于我</a>
    </li>
    
  </ul>
</nav>
<nav class="navbar navbar-bottom">
  <ul class="nav">
    <li class="nav-item">
      
      <a class="nav-item-link nav-item-search"  title="搜索">
        <i class="ri-search-line"></i>
      </a>
      
      
      <a class="nav-item-link" target="_blank" href="/atom.xml" title="RSS Feed">
        <i class="ri-rss-line"></i>
      </a>
      
    </li>
  </ul>
</nav>
<div class="search-form-wrap">
  <div class="local-search local-search-plugin">
  <input type="search" id="local-search-input" class="local-search-input" placeholder="Search...">
  <div id="local-search-result" class="local-search-result"></div>
</div>
</div>
    </aside>
    <div id="mask"></div>

<!-- #reward -->
<div id="reward">
  <span class="close"><i class="ri-close-line"></i></span>
  <p class="reward-p"><i class="ri-cup-line"></i>请我喝杯咖啡吧~</p>
  <div class="reward-box">
    
    <div class="reward-item">
      <img class="reward-img" src="/images/alipay.jpg">
      <span class="reward-type">支付宝</span>
    </div>
    
    
    <div class="reward-item">
      <img class="reward-img" src="/images/wechatpay.jpg">
      <span class="reward-type">微信</span>
    </div>
    
  </div>
</div>
    
<script src="/js/jquery-3.6.0.min.js"></script>
 
<script src="/js/lazyload.min.js"></script>

<!-- Tocbot -->
 
<script src="/js/tocbot.min.js"></script>

<script>
  tocbot.init({
    tocSelector: ".tocbot",
    contentSelector: ".article-entry",
    headingSelector: "h1, h2, h3, h4, h5, h6",
    hasInnerContainers: true,
    scrollSmooth: true,
    scrollContainer: "main",
    positionFixedSelector: ".tocbot",
    positionFixedClass: "is-position-fixed",
    fixedSidebarOffset: "auto",
  });
</script>

<script src="https://cdn.jsdelivr.net/npm/jquery-modal@0.9.2/jquery.modal.min.js"></script>
<link
  rel="stylesheet"
  href="https://cdn.jsdelivr.net/npm/jquery-modal@0.9.2/jquery.modal.min.css"
/>
<script src="https://cdn.jsdelivr.net/npm/justifiedGallery@3.7.0/dist/js/jquery.justifiedGallery.min.js"></script>

<script src="/dist/main.js"></script>

<!-- ImageViewer -->
 <!-- Root element of PhotoSwipe. Must have class pswp. -->
<div class="pswp" tabindex="-1" role="dialog" aria-hidden="true">

    <!-- Background of PhotoSwipe. 
         It's a separate element as animating opacity is faster than rgba(). -->
    <div class="pswp__bg"></div>

    <!-- Slides wrapper with overflow:hidden. -->
    <div class="pswp__scroll-wrap">

        <!-- Container that holds slides. 
            PhotoSwipe keeps only 3 of them in the DOM to save memory.
            Don't modify these 3 pswp__item elements, data is added later on. -->
        <div class="pswp__container">
            <div class="pswp__item"></div>
            <div class="pswp__item"></div>
            <div class="pswp__item"></div>
        </div>

        <!-- Default (PhotoSwipeUI_Default) interface on top of sliding area. Can be changed. -->
        <div class="pswp__ui pswp__ui--hidden">

            <div class="pswp__top-bar">

                <!--  Controls are self-explanatory. Order can be changed. -->

                <div class="pswp__counter"></div>

                <button class="pswp__button pswp__button--close" title="Close (Esc)"></button>

                <button class="pswp__button pswp__button--share" style="display:none" title="Share"></button>

                <button class="pswp__button pswp__button--fs" title="Toggle fullscreen"></button>

                <button class="pswp__button pswp__button--zoom" title="Zoom in/out"></button>

                <!-- Preloader demo http://codepen.io/dimsemenov/pen/yyBWoR -->
                <!-- element will get class pswp__preloader--active when preloader is running -->
                <div class="pswp__preloader">
                    <div class="pswp__preloader__icn">
                        <div class="pswp__preloader__cut">
                            <div class="pswp__preloader__donut"></div>
                        </div>
                    </div>
                </div>
            </div>

            <div class="pswp__share-modal pswp__share-modal--hidden pswp__single-tap">
                <div class="pswp__share-tooltip"></div>
            </div>

            <button class="pswp__button pswp__button--arrow--left" title="Previous (arrow left)">
            </button>

            <button class="pswp__button pswp__button--arrow--right" title="Next (arrow right)">
            </button>

            <div class="pswp__caption">
                <div class="pswp__caption__center"></div>
            </div>

        </div>

    </div>

</div>

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/photoswipe@4.1.3/dist/photoswipe.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/photoswipe@4.1.3/dist/default-skin/default-skin.min.css">
<script src="https://cdn.jsdelivr.net/npm/photoswipe@4.1.3/dist/photoswipe.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/photoswipe@4.1.3/dist/photoswipe-ui-default.min.js"></script>

<script>
    function viewer_init() {
        let pswpElement = document.querySelectorAll('.pswp')[0];
        let $imgArr = document.querySelectorAll(('.article-entry img:not(.reward-img)'))

        $imgArr.forEach(($em, i) => {
            $em.onclick = () => {
                // slider展开状态
                // todo: 这样不好，后面改成状态
                if (document.querySelector('.left-col.show')) return
                let items = []
                $imgArr.forEach(($em2, i2) => {
                    let img = $em2.getAttribute('data-idx', i2)
                    let src = $em2.getAttribute('data-target') || $em2.getAttribute('src')
                    let title = $em2.getAttribute('alt')
                    // 获得原图尺寸
                    const image = new Image()
                    image.src = src
                    items.push({
                        src: src,
                        w: image.width || $em2.width,
                        h: image.height || $em2.height,
                        title: title
                    })
                })
                var gallery = new PhotoSwipe(pswpElement, PhotoSwipeUI_Default, items, {
                    index: parseInt(i)
                });
                gallery.init()
            }
        })
    }
    viewer_init()
</script> 
<!-- MathJax -->

<!-- Katex -->
 
    
        <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.11.1/dist/katex.min.css">
        <script src="https://cdn.jsdelivr.net/npm/katex@0.11.1/dist/katex.min.js"></script>
        <script src="https://cdn.jsdelivr.net/npm/katex@0.11.1/dist/contrib/auto-render.min.js"></script>
        
    
 
<!-- busuanzi  -->
 
<script src="/js/busuanzi-2.3.pure.min.js"></script>
 
<!-- ClickLove -->

<!-- ClickBoom1 -->

<!-- ClickBoom2 -->

<!-- CodeCopy -->
 
<link rel="stylesheet" href="/css/clipboard.css">
 <script src="https://cdn.jsdelivr.net/npm/clipboard@2/dist/clipboard.min.js"></script>
<script>
  function wait(callback, seconds) {
    var timelag = null;
    timelag = window.setTimeout(callback, seconds);
  }
  !function (e, t, a) {
    var initCopyCode = function(){
      var copyHtml = '';
      copyHtml += '<button class="btn-copy" data-clipboard-snippet="">';
      copyHtml += '<i class="ri-file-copy-2-line"></i><span>COPY</span>';
      copyHtml += '</button>';
      $(".highlight .code pre").before(copyHtml);
      $(".article pre code").before(copyHtml);
      var clipboard = new ClipboardJS('.btn-copy', {
        target: function(trigger) {
          return trigger.nextElementSibling;
        }
      });
      clipboard.on('success', function(e) {
        let $btn = $(e.trigger);
        $btn.addClass('copied');
        let $icon = $($btn.find('i'));
        $icon.removeClass('ri-file-copy-2-line');
        $icon.addClass('ri-checkbox-circle-line');
        let $span = $($btn.find('span'));
        $span[0].innerText = 'COPIED';
        
        wait(function () { // 等待两秒钟后恢复
          $icon.removeClass('ri-checkbox-circle-line');
          $icon.addClass('ri-file-copy-2-line');
          $span[0].innerText = 'COPY';
        }, 2000);
      });
      clipboard.on('error', function(e) {
        e.clearSelection();
        let $btn = $(e.trigger);
        $btn.addClass('copy-failed');
        let $icon = $($btn.find('i'));
        $icon.removeClass('ri-file-copy-2-line');
        $icon.addClass('ri-time-line');
        let $span = $($btn.find('span'));
        $span[0].innerText = 'COPY FAILED';
        
        wait(function () { // 等待两秒钟后恢复
          $icon.removeClass('ri-time-line');
          $icon.addClass('ri-file-copy-2-line');
          $span[0].innerText = 'COPY';
        }, 2000);
      });
    }
    initCopyCode();
  }(window, document);
</script>
 
<!-- CanvasBackground -->

<script>
  if (window.mermaid) {
    mermaid.initialize({ theme: "forest" });
  }
</script>


    
    <div id="music">
    
    
    
    <iframe frameborder="no" border="1" marginwidth="0" marginheight="0" width="200" height="52"
        src="//music.163.com/outchain/player?type=2&id=22707008&auto=1&height=32"></iframe>
</div>

<style>
    #music {
        position: fixed;
        right: 15px;
        bottom: 0;
        z-index: 998;
    }
</style>
    
    

  </div>
</body>

</html>